package com.cyt.chattlibrary.face;


import android.content.Context;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.Log;

import com.cyt.chattlibrary.R;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A class for annotating a CharSequence with spans to convert textual emoticons
 * to graphical ones.
 */
public class SmileyParser {
    // Singleton stuff

    public static final int DEFAULT_SMILEY_TEXTS = R.array.default_smiley_texts;
    public static final int DEFAULT_SMILEY_NAMES = R.array.default_smiley_names;
    private static SmileyParser sInstance;
    private final Context mContext;
    private final String[] mSmileyTexts;
    private final String[] mSmileyNames;
    private final Pattern mPattern, sinaPatten;
    private final HashMap<String, Integer> mSmileyToRes;
    private final HashMap<String, String> mSmileyToText;
    private final int[] DEFAULT_SMILEY_RES_IDS;

    private SmileyParser(Context context) {
        mContext = context;
        mSmileyTexts = mContext.getResources().getStringArray(DEFAULT_SMILEY_TEXTS);
        mSmileyNames = mContext.getResources().getStringArray(DEFAULT_SMILEY_NAMES);
        DEFAULT_SMILEY_RES_IDS = buildSmileyRes();
        mSmileyToRes = buildSmileyToRes();
        mSmileyToText = buildSmileyToText();
        mPattern = buildPattern();

        sinaPatten = buildSinaPatten();
    }

    /**
     * 初始化表情资源
     *
     * @return
     */
    private int[] buildSmileyRes() {
        int[] is = new int[mSmileyNames.length];
        for (int t = 0; t < mSmileyNames.length; t++) {
            try {

                Field filed = R.drawable.class.getDeclaredField(mSmileyNames[t]);
                int resourceId = Integer.parseInt(filed.get(null).toString());
                is[t] = resourceId;

            } catch (SecurityException | IllegalArgumentException | NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return is;
    }

    /**
     * Builds the hashtable we use for mapping the string version
     * of a smiley (e.g. ":-)") to a resource ID for the icon version.
     */
    private HashMap<String, Integer> buildSmileyToRes() {
        if (DEFAULT_SMILEY_RES_IDS.length != mSmileyTexts.length) {
            // Throw an exception if someone updated DEFAULT_SMILEY_RES_IDS

            // and failed to update arrays.xml

            throw new IllegalStateException("Smiley resource ID/text mismatch");
        }

        HashMap<String, Integer> smileyToRes =
                new HashMap<String, Integer>();
        for (int i = 0; i < mSmileyTexts.length; i++) {
            smileyToRes.put(mSmileyTexts[i], DEFAULT_SMILEY_RES_IDS[i]);
        }

        return smileyToRes;
    }

    private HashMap<String, String> buildSmileyToText() {
        if (DEFAULT_SMILEY_RES_IDS.length != mSmileyNames.length) {
            // Throw an exception if someone updated DEFAULT_SMILEY_RES_IDS

            // and failed to update arrays.xml

            throw new IllegalStateException("Smiley resource ID/text mismatch");
        }

        HashMap<String, String> smileyToRes =
                new HashMap<String, String>();
        for (int i = 0; i < mSmileyNames.length; i++) {
            smileyToRes.put(mSmileyNames[i], mSmileyTexts[i]);
        }

        return smileyToRes;
    }

    /**
     * Builds the regular expression we use to find smileys in {@link #addSmileySpans}.
     */
    //构建正则表达式
    private Pattern buildPattern() {
        // Set the StringBuilder capacity with the assumption that the average

        // smiley is 3 characters long.

        StringBuilder patternString = new StringBuilder(mSmileyTexts.length * 3);

        // Build a regex that looks like (:-)|:-(|...), but escaping the smilies

        // properly so they will be interpreted literally by the regex matcher.

        patternString.append('(');
        for (String s : mSmileyTexts) {
            patternString.append(Pattern.quote(s));
            patternString.append('|');
        }
        // Replace the extra '|' with a ')'

        patternString.replace(patternString.length() - 1, patternString.length(), ")");

        return Pattern.compile(patternString.toString());
    }

    private Pattern buildSinaPatten() {
        StringBuilder patternString = new StringBuilder(mSmileyNames.length * 3);

        // Build a regex that looks like (:-)|:-(|...), but escaping the smilies

        // properly so they will be interpreted literally by the regex matcher.

        patternString.append('(');
        for (String s : mSmileyNames) {
            patternString.append(Pattern.quote(s));
            patternString.append('|');
        }
        patternString.replace(patternString.length() - 1, patternString.length(), ")");

        return Pattern.compile(patternString.toString());
    }

    public static SmileyParser getInstance() {
        return sInstance;
    }

    public static void init(Context context) {
        sInstance = new SmileyParser(context);
    }

    public Pattern getPattern() {
        return mPattern;
    }

    /**
     * 得到一个SpanableString对象，通过传入的SpanableString对象,并进行正则判断
     *
     * @return
     */
    public String getExpressionString(String str/*SpannableString spannableString*/) {
        //    	SpannableString spannableString = new SpannableString(str);
        String result = null;
        //通过传入的正则表达式来生成一个pattern

        // Replace the extra '|' with a ')'

        try {
            result = dealExpression(str, sinaPatten, 0);
        } catch (Exception e) {
            Log.e("dealExpression", e.getMessage());
        }
        return result;
    }

    /**
     * 对spanableString进行正则判断，如果符合要求，则以表情图片代替
     *
     * @param patten
     * @param start
     * @throws SecurityException
     * @throws NumberFormatException
     * @throws IllegalArgumentException
     */
    public String dealExpression(String str, Pattern patten, int start) throws SecurityException, NumberFormatException, IllegalArgumentException {
        Matcher matcher = patten.matcher(str);
        while (matcher.find()) {
            String key = matcher.group();
            if (matcher.start() < start) {
                continue;
            }
            String text = mSmileyToText.get(key);
            if (!TextUtils.isEmpty(text)) {
                str = str.replace(key, text);
            }
        }
        return str;
    }

    /**
     * Adds ImageSpans to a CharSequence that replace textual emoticons such
     * as :-) with a graphical version.
     *
     * @param text A CharSequence possibly containing emoticons
     * @return A CharSequence annotated with ImageSpans covering any
     * recognized emoticons.
     */
    //根据文本替换成图片
    public SpannableStringBuilder addSmileySpans(CharSequence text, float textSize) {
        SpannableStringBuilder builder = new SpannableStringBuilder(text);
        Matcher matcher = mPattern.matcher(text);
        while (matcher.find()) {
            int resId = mSmileyToRes.get(matcher.group());
            builder.setSpan(EmotionManager.getImageSpan(mContext, resId, textSize),
                    matcher.start(), matcher.end(),
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        return builder;
    }
}

